#include "fxcc/core/graph/opengl3/ImGuiGlfwApp.h"
#include "fxcc/core/graph/opengl3/PickupEffect.h"
#include "fxcc/core/graph/common/Geometry.h"
#include "fxcc/imgui/Editor.h"

#define IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED
#include "imgui.h"
#include "imgui_internal.h"
#include "ImGuizmo.h"


using namespace fxcc::platform;
using namespace fxcc::graph;
using namespace fxcc::graph::opengl3;
using namespace fxcc::imgui::graph::opengl3;
using BaseApp = fxcc::imgui::graph::opengl3::GlfwApp;

#undef main

#define NUM 32

struct Obj
{
    int objId{ -1 };
    fxcc::graph::common::Transform transform;

};
struct SimpleApp : public BaseApp
{
public:
    fxcc::graph::common::Transform transform;

    std::shared_ptr<fxcc::graph::opengl3::RenderTargetJack> m_RenderTarget;
    std::shared_ptr<fxcc::graph::opengl3::MeshJack> m_CubeMesh;

    glm::vec4 color;
    std::shared_ptr<fxcc::graph::opengl3::PickupEffect> m_Effect;

    fxcc::graph::common::Camera camera;
    std::vector<Obj> m_Objs;
    SimpleApp(const fxcc::platform::common::App::Desc &desc) : BaseApp(desc), color(1.0)
    {
    }
    bool Init() override
    {
        if (!BaseApp::Init())
        {
            return false;
        }

        if (!InitResources())
        {
            return false;
        }

        return true;
    };

    bool InitResources()
    {

        camera.SetPosition(glm::vec3(5.0f));
        camera.LookAt(glm::vec3(0.0f));

        m_Effect = std::make_shared<fxcc::graph::opengl3::PickupEffect>(true);
        auto geoData = fxcc::graph::common::Geometry::CreateBox();
        m_CubeMesh = std::make_shared<fxcc::graph::opengl3::MeshJack>(geoData);

        m_Objs.resize(NUM);
        fxcc::graph::common::Random random;
        glm::vec3 pos[NUM];
        glm::vec3 rot[NUM];

        random.GetVec3(&pos[0], NUM, glm::vec3(-10.0f), glm::vec3(10.0f));
        random.GetVec3(&rot[0], NUM, glm::vec3(-180.0f), glm::vec3(180.0f));

        for (int i = 0; i < NUM; i++)
        {
            auto& o = m_Objs[i];
            auto& t = o.transform;
            t.m_Rotation = rot[i];
            t.m_Position = pos[i];
            o.objId = i;

        }

        return true;
    };

    fxcc::imgui::Editor editor;
    ;

    int pickedID{0};

    void EditTransform(const glm::mat4& proj, const glm::mat4& view, glm::mat4& world)
    {
        ImGuiIO& io = ImGui::GetIO();
        float windowWidth = (float)ImGui::GetWindowWidth();
        float windowHeight = (float)ImGui::GetWindowHeight();
        bool useWindow = true;
        ImGuizmo::SetRect(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, windowWidth, windowHeight);
        ImGuizmo::Manipulate(&view[0][0], &proj[0][0], ImGuizmo::TRANSLATE, ImGuizmo::WORLD, &world[0][0], NULL);
    }

    void OnEdit() override
    {
        ImGuiIO& io = ImGui::GetIO();

        ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());

        ImGui::Begin("Hello world");
        ImGui::Text("pickid is %d", pickedID);

        if (pickedID > 0 && pickedID < NUM + 1)
        {
            auto& o = m_Objs[pickedID - 1];
            editor.EditInst<int>("id", o.objId);
            editor.EditInst<fxcc::graph::common::Transform>("", o.transform);

        }

        ImGui::End();


        ImGui::Begin("Frame");


        if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
        {

            int mouseX = io.MousePos.x;
            int mouseY = io.MousePos.y;
            ImVec2 sz = ImGui::GetContentRegionAvail();

            glm::vec2 posAxis;
            posAxis.x = (float)mouseX / (float)sz.x;
            posAxis.y = (float)mouseY / (float)sz.y;
            posAxis.y = 1 - posAxis.y;


            pickedID = m_RenderTarget->GetPickupIndexAxis(0, posAxis);

        }
        editor.AddFrameBuffer(m_RenderTarget->m_Textures[0]->GetTextureId());


        ImGuizmo::SetOrthographic(false);
        ImGuizmo::BeginFrame();
        ImGuizmo::SetDrawlist();

        float windowWidth = (float)ImGui::GetWindowWidth();
        float windowHeight = (float)ImGui::GetWindowHeight();
        ImGuizmo::SetRect(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, windowWidth, windowHeight);

        auto viewManipulateRight = ImGui::GetWindowPos().x + windowWidth;
        auto viewManipulateTop = ImGui::GetWindowPos().y;
        ImGuiWindow* window = ImGui::GetCurrentWindow();

        auto gizmoWindowFlags = ImGui::IsWindowHovered() && ImGui::IsMouseHoveringRect(window->InnerRect.Min, window->InnerRect.Max) ? ImGuiWindowFlags_NoMove : 0;


        if (pickedID > 0)
        {

            auto& obj = m_Objs[pickedID - 1];

            glm::mat4 world = obj.transform.GetWorld();
            glm::mat4 proj = camera.GetProjection();
            glm::mat4 view = camera.GetViewMatrix();

            EditTransform(proj, view, world);

            obj.transform.Decompose(world);
        }

        ImGui::End();
    }
    void OnDestroy() override
    {
      
        BaseApp::OnDestroy();
    }
    void OnFrameRender() override
    {
        glViewport(0, 0, m_Desc.m_Size.x, m_Desc.m_Size.y);

        glClearColor(color.x, color.y, color.z, color.w);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        m_RenderTarget->Begin();

        glClearColor(
            0, 0, 0, 1);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        m_Effect->Begin();

        m_Effect->SetCamera(camera);
        
        for (const auto& o : m_Objs)
        {
            fxcc::graph::common::Effect3d::ObjData objData(o.transform);
            objData.objId = o.objId + 1;
            m_Effect->SetObjData(objData);
            m_Effect->InstMeshJack(m_CubeMesh.get());
        }
        m_Effect->End();
        
        m_RenderTarget->End();

    };

    void OnFramebuffersize(int w, int h) override
    {
        opengl3::GlfwApp::OnFramebuffersize(w, h);
        camera.SetAspect(m_Desc.Aspect());

        {
            fxcc::graph::common::RenderTargetJack::Desc desc(1, { w, h, 4,0 });
        	m_RenderTarget = std::make_shared<fxcc::graph::opengl3::RenderTargetJack>(desc);
        }
    }
    void OnUpdate() override
    {
        opengl3::GlfwApp::OnUpdate();

        float ctTime = m_GlfwlTimer.m_CurrentTime;
        //camera.FreeMove(m_Input, m_GlfwlTimer.m_DeltaTime);

        float deltaTime = m_GlfwlTimer.m_DeltaTime;


     
    }
};

int main()
{
    ztclog::pushFunction([](const ztclog::Line &line)
                         {
		if (line.m_Type != ztclog::Line::Type::_line_debug_)
		{
			std::cout << line.m_Text << std::endl;
		} });

    using _App = SimpleApp;
    using _Desc = fxcc::platform::common::App::Desc;

    _Desc desc;
    desc.m_Pos = glm::ivec2(100, 100);
    desc.m_Size = glm::ivec2(900, 600);
    desc.m_ScaleFactor = 1.0f;

    desc.m_Title = "test font";
    std::shared_ptr<_App> _app = std::make_shared<_App>(desc);
    return _app->Run();
};
